package com.fang.algorithm.leecode;

import java.util.HashMap;
import java.util.Map;

/**
 * @author fanglingxiao
 * @version 1.0
 * @description 从前序遍历与中序遍历构造二叉树
 * 给定两个整数数组preorder 和 inorder，其中preorder 是二叉树的先序遍历， inorder是同一棵树的中序遍历，请构造二叉树并返回其根节点
 * <p>
 * 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
 * 输出: [3,9,20,null,null,15,7]
 * <p>
 * 输入: preorder = [-1], inorder = [-1]
 * 输出: [-1]
 * <p>
 * 提示:
 * <p>
 * 1 <= preorder.length <= 3000
 * inorder.length == preorder.length
 * -3000 <= preorder[i], inorder[i] <= 3000
 * preorder和inorder均 无重复 元素
 * inorder均出现在preorder
 * preorder保证 为二叉树的前序遍历序列
 * inorder保证 为二叉树的中序遍历序列
 * @date 2022/5/22 3:46 下午
 **/
public class L105_BuildTree {
    private static final Map<Integer, Integer> INDEX_MAP = new HashMap<>();

    public static void main(String[] args) {
        int[] preorder = new int[]{3, 9, 20, 15, 7};
        int[] inorder = new int[]{9, 3, 15, 20, 7};
        TreeNode ans = buildTree(preorder, inorder);
        printTreeNode(ans);
    }

    private static TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        for (int i = 0; i < n; i++) {
            INDEX_MAP.put(inorder[i], i);
        }
        return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
    }

    private static TreeNode myBuildTree(int[] preorder, int[] inorder, int preLeft, int preRight, int inLeft, int inRight) {
        if (preLeft > preRight) {
            return null;
        }
        // 前序遍历第一个节点为root
        int preRoot = preLeft;
        // 在中序遍历中找到root位置
        int rootValue = preorder[preRoot];
        int inRoot = INDEX_MAP.get(rootValue);
        // 建立root节点
        TreeNode root = new TreeNode(rootValue);
        // 获取左子树的节点数目 中序遍历的root的位置 - 中序遍历的开始位置
        int leftSizeSub = inRoot - inLeft;
        root.left = myBuildTree(preorder, inorder, preLeft + 1, preLeft + leftSizeSub, inLeft, inRoot - 1);
        root.right = myBuildTree(preorder, inorder, preLeft + leftSizeSub + 1, preRight, inRoot + 1, inRight);
        return root;
    }

    private static void printTreeNode(TreeNode node) {
        if (node == null) {
            System.out.print("null ->");
            return;
        }
        System.out.print(node.val + "->");
        printTreeNode(node.left);
        printTreeNode(node.right);
    }

    public static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;

        TreeNode() {
        }

        TreeNode(int val) {
            this.val = val;
        }

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

}
